home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / game / shoot / ADoomPPC_src.lha / ADoomPPC_src / m_menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-14  |  32.9 KB  |  1,914 lines

  1. // Emacs style mode select   -*- C++ -*- 
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:
  20. //    DOOM selection menu, options, episode etc.
  21. //    Sliders and icons. Kinda widget stuff.
  22. //
  23. //-----------------------------------------------------------------------------
  24.  
  25. static const char
  26. rcsid[] = "$Id: m_menu.c,v 1.7 1997/02/03 22:45:10 b1 Exp $";
  27.  
  28. #ifndef __VBCC__
  29. #include <unistd.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33. #endif
  34. #include <stdlib.h>
  35. #include <ctype.h>
  36.  
  37.  
  38. #include "doomdef.h"
  39. #include "dstrings.h"
  40.  
  41. #include "d_main.h"
  42.  
  43. #include "i_system.h"
  44. #include "i_video.h"
  45. #include "z_zone.h"
  46. #include "v_video.h"
  47. #include "w_wad.h"
  48.  
  49. #include "r_local.h"
  50.  
  51.  
  52. #include "hu_stuff.h"
  53.  
  54. #include "g_game.h"
  55.  
  56. #include "m_argv.h"
  57. #include "m_swap.h"
  58.  
  59. #include "s_sound.h"
  60.  
  61. #include "doomstat.h"
  62.  
  63. // Data.
  64. #include "sounds.h"
  65.  
  66. #include "m_menu.h"
  67.  
  68.  
  69.  
  70. extern patch_t*        hu_font[HU_FONTSIZE];
  71. extern boolean        message_dontfuckwithme;
  72.  
  73. extern boolean        chat_on;        // in heads-up code
  74.  
  75. //
  76. // defaulted values
  77. //
  78. int            mouseSensitivity;       // has default
  79.  
  80. // Show messages has default, 0 = off, 1 = on
  81. int            showMessages;
  82.     
  83.  
  84. // Blocky mode, has default, 0 = high, 1 = normal
  85. int            detailLevel;        
  86. int            screenblocks;        // has default
  87.  
  88. // temp for screenblocks (0-9)
  89. int            screenSize;        
  90.  
  91. // -1 = no quicksave slot picked!
  92. int            quickSaveSlot;          
  93.  
  94.  // 1 = message to be printed
  95. int            messageToPrint;
  96. // ...and here is the message string!
  97. char*            messageString;        
  98.  
  99. // message x & y
  100. int            messx;            
  101. int            messy;
  102. int            messageLastMenuActive;
  103.  
  104. // timed message = no input from user
  105. boolean            messageNeedsInput;     
  106.  
  107. void    (*messageRoutine)(int response);
  108.  
  109. #define SAVESTRINGSIZE     24
  110.  
  111. char gammamsg[5][26] =
  112. {
  113.     GAMMALVL0,
  114.     GAMMALVL1,
  115.     GAMMALVL2,
  116.     GAMMALVL3,
  117.     GAMMALVL4
  118. };
  119.  
  120. // we are going to be entering a savegame string
  121. int            saveStringEnter;              
  122. int                 saveSlot;    // which slot to save in
  123. int            saveCharIndex;    // which char we're editing
  124. // old save description before edit
  125. char            saveOldString[SAVESTRINGSIZE];  
  126.  
  127. boolean            inhelpscreens;
  128. boolean            menuactive;
  129.  
  130. #define SKULLXOFF        -32
  131. #define LINEHEIGHT        16
  132.  
  133. extern boolean        sendpause;
  134. char            savegamestrings[10][SAVESTRINGSIZE];
  135.  
  136. char    endstring[160];
  137.  
  138.  
  139. //
  140. // MENU TYPEDEFS
  141. //
  142. typedef struct
  143. {
  144.     // 0 = no cursor here, 1 = ok, 2 = arrows ok
  145.     short    status;
  146.     
  147.     char    name[10];
  148.     
  149.     // choice = menu item #.
  150.     // if status = 2,
  151.     //   choice=0:leftarrow,1:rightarrow
  152.     void    (*routine)(int choice);
  153.     
  154.     // hotkey in menu
  155.     char    alphaKey;            
  156. } menuitem_t;
  157.  
  158.  
  159.  
  160. typedef struct menu_s
  161. {
  162.     short        numitems;    // # of menu items
  163.     struct menu_s*    prevMenu;    // previous menu
  164.     menuitem_t*        menuitems;    // menu items
  165.     void        (*routine)(void); // draw routine
  166.     short        x;
  167.     short        y;        // x,y of menu
  168.     short        lastOn;        // last item user was on in menu
  169. } menu_t;
  170.  
  171. short        itemOn;            // menu item skull is on
  172. short        skullAnimCounter;    // skull animation counter
  173. short        whichSkull;        // which skull to draw
  174.  
  175. // graphic name of skulls
  176. // warning: initializer-string for array of chars is too long
  177. char    skullName[2][/*8*/9] = {"M_SKULL1","M_SKULL2"};
  178.  
  179. // current menudef
  180. menu_t*    currentMenu;                          
  181.  
  182. //
  183. // PROTOTYPES
  184. //
  185. void M_NewGame(int choice);
  186. void M_Episode(int choice);
  187. void M_ChooseSkill(int choice);
  188. void M_LoadGame(int choice);
  189. void M_SaveGame(int choice);
  190. void M_Options(int choice);
  191. void M_EndGame(int choice);
  192. void M_ReadThis(int choice);
  193. void M_ReadThis2(int choice);
  194. void M_QuitDOOM(int choice);
  195.  
  196. void M_ChangeMessages(int choice);
  197. void M_ChangeSensitivity(int choice);
  198. void M_SfxVol(int choice);
  199. void M_MusicVol(int choice);
  200. void M_ChangeDetail(int choice);
  201. void M_SizeDisplay(int choice);
  202. void M_StartGame(int choice);
  203. void M_Sound(int choice);
  204.  
  205. void M_FinishReadThis(int choice);
  206. void M_LoadSelect(int choice);
  207. void M_SaveSelect(int choice);
  208. void M_ReadSaveStrings(void);
  209. void M_QuickSave(void);
  210. void M_QuickLoad(void);
  211.  
  212. void M_DrawMainMenu(void);
  213. void M_DrawReadThis1(void);
  214. void M_DrawReadThis2(void);
  215. void M_DrawNewGame(void);
  216. void M_DrawEpisode(void);
  217. void M_DrawOptions(void);
  218. void M_DrawSound(void);
  219. void M_DrawLoad(void);
  220. void M_DrawSave(void);
  221.  
  222. void M_DrawSaveLoadBorder(int x,int y);
  223. void M_SetupNextMenu(menu_t *menudef);
  224. void M_DrawThermo(int x,int y,int thermWidth,int thermDot);
  225. void M_DrawEmptyCell(menu_t *menu,int item);
  226. void M_DrawSelCell(menu_t *menu,int item);
  227. void M_WriteText(int x, int y, char *string);
  228. int  M_StringWidth(char *string);
  229. int  M_StringHeight(char *string);
  230. void M_StartControlPanel(void);
  231. void M_StartMessage(char *string,void (*routine)(int response),boolean input);
  232. void M_StopMessage(void);
  233. void M_ClearMenus (void);
  234.  
  235.  
  236.  
  237.  
  238. //
  239. // DOOM MENU
  240. //
  241. enum
  242. {
  243.     newgame = 0,
  244.     options,
  245.     loadgame,
  246.     savegame,
  247.     readthis,
  248.     quitdoom,
  249.     main_end
  250. } main_e;
  251.  
  252. menuitem_t MainMenu[]=
  253. {
  254.     {1,"M_NGAME",M_NewGame,'n'},
  255.     {1,"M_OPTION",M_Options,'o'},
  256.     {1,"M_LOADG",M_LoadGame,'l'},
  257.     {1,"M_SAVEG",M_SaveGame,'s'},
  258.     // Another hickup with Special edition.
  259.     {1,"M_RDTHIS",M_ReadThis,'r'},
  260.     {1,"M_QUITG",M_QuitDOOM,'q'}
  261. };
  262.  
  263. menu_t  MainDef =
  264. {
  265.     main_end,
  266.     NULL,
  267.     MainMenu,
  268.     M_DrawMainMenu,
  269.     97,64,
  270.     0
  271. };
  272.  
  273.  
  274. //
  275. // EPISODE SELECT
  276. //
  277. enum
  278. {
  279.     ep1,
  280.     ep2,
  281.     ep3,
  282.     ep4,
  283.     ep_end
  284. } episodes_e;
  285.  
  286. menuitem_t EpisodeMenu[]=
  287. {
  288.     {1,"M_EPI1", M_Episode,'k'},
  289.     {1,"M_EPI2", M_Episode,'t'},
  290.     {1,"M_EPI3", M_Episode,'i'},
  291.     {1,"M_EPI4", M_Episode,'t'}
  292. };
  293.  
  294. menu_t  EpiDef =
  295. {
  296.     ep_end,        // # of menu items
  297.     &MainDef,        // previous menu
  298.     EpisodeMenu,    // menuitem_t ->
  299.     M_DrawEpisode,    // drawing routine ->
  300.     48,63,              // x,y
  301.     ep1            // lastOn
  302. };
  303.  
  304. //
  305. // NEW GAME
  306. //
  307. enum
  308. {
  309.     killthings,
  310.     toorough,
  311.     hurtme,
  312.     violence,
  313.     nightmare,
  314.     newg_end
  315. } newgame_e;
  316.  
  317. menuitem_t NewGameMenu[]=
  318. {
  319.     {1,"M_JKILL",    M_ChooseSkill, 'i'},
  320.     {1,"M_ROUGH",    M_ChooseSkill, 'h'},
  321.     {1,"M_HURT",    M_ChooseSkill, 'h'},
  322.     {1,"M_ULTRA",    M_ChooseSkill, 'u'},
  323.     {1,"M_NMARE",    M_ChooseSkill, 'n'}
  324. };
  325.  
  326. menu_t  NewDef =
  327. {
  328.     newg_end,        // # of menu items
  329.     &EpiDef,        // previous menu
  330.     NewGameMenu,    // menuitem_t ->
  331.     M_DrawNewGame,    // drawing routine ->
  332.     48,63,              // x,y
  333.     hurtme        // lastOn
  334. };
  335.  
  336.  
  337.  
  338. //
  339. // OPTIONS MENU
  340. //
  341. enum
  342. {
  343.     endgame,
  344.     messages,
  345.     detail,
  346.     scrnsize,
  347.     option_empty1,
  348.     mousesens,
  349.     option_empty2,
  350.     soundvol,
  351.     opt_end
  352. } options_e;
  353.  
  354. menuitem_t OptionsMenu[]=
  355. {
  356.     {1,"M_ENDGAM",    M_EndGame,'e'},
  357.     {1,"M_MESSG",    M_ChangeMessages,'m'},
  358.     {1,"M_DETAIL",    M_ChangeDetail,'g'},
  359.     {2,"M_SCRNSZ",    M_SizeDisplay,'s'},
  360.     {-1,"",0},
  361.     {2,"M_MSENS",    M_ChangeSensitivity,'m'},
  362.     {-1,"",0},
  363.     {1,"M_SVOL",    M_Sound,'s'}
  364. };
  365.  
  366. menu_t  OptionsDef =
  367. {
  368.     opt_end,
  369.     &MainDef,
  370.     OptionsMenu,
  371.     M_DrawOptions,
  372.     60,37,
  373.     0
  374. };
  375.  
  376. //
  377. // Read This! MENU 1 & 2
  378. //
  379. enum
  380. {
  381.     rdthsempty1,
  382.     read1_end
  383. } read_e;
  384.  
  385. menuitem_t ReadMenu1[] =
  386. {
  387.     {1,"",M_ReadThis2,0}
  388. };
  389.  
  390. menu_t  ReadDef1 =
  391. {
  392.     read1_end,
  393.     &MainDef,
  394.     ReadMenu1,
  395.     M_DrawReadThis1,
  396.     280,185,
  397.     0
  398. };
  399.  
  400. enum
  401. {
  402.     rdthsempty2,
  403.     read2_end
  404. } read_e2;
  405.  
  406. menuitem_t ReadMenu2[]=
  407. {
  408.     {1,"",M_FinishReadThis,0}
  409. };
  410.  
  411. menu_t  ReadDef2 =
  412. {
  413.     read2_end,
  414.     &ReadDef1,
  415.     ReadMenu2,
  416.     M_DrawReadThis2,
  417.     330,175,
  418.     0
  419. };
  420.  
  421. //
  422. // SOUND VOLUME MENU
  423. //
  424. enum
  425. {
  426.     sfx_vol,
  427.     sfx_empty1,
  428.     music_vol,
  429.     sfx_empty2,
  430.     sound_end
  431. } sound_e;
  432.  
  433. menuitem_t SoundMenu[]=
  434. {
  435.     {2,"M_SFXVOL",M_SfxVol,'s'},
  436.     {-1,"",0},
  437.     {2,"M_MUSVOL",M_MusicVol,'m'},
  438.     {-1,"",0}
  439. };
  440.  
  441. menu_t  SoundDef =
  442. {
  443.     sound_end,
  444.     &OptionsDef,
  445.     SoundMenu,
  446.     M_DrawSound,
  447.     80,64,
  448.     0
  449. };
  450.  
  451. //
  452. // LOAD GAME MENU
  453. //
  454. enum
  455. {
  456.     load1,
  457.     load2,
  458.     load3,
  459.     load4,
  460.     load5,
  461.     load6,
  462.     load_end
  463. } load_e;
  464.  
  465. menuitem_t LoadMenu[]=
  466. {
  467.     {1,"", M_LoadSelect,'1'},
  468.     {1,"", M_LoadSelect,'2'},
  469.     {1,"", M_LoadSelect,'3'},
  470.     {1,"", M_LoadSelect,'4'},
  471.     {1,"", M_LoadSelect,'5'},
  472.     {1,"", M_LoadSelect,'6'}
  473. };
  474.  
  475. menu_t  LoadDef =
  476. {
  477.     load_end,
  478.     &MainDef,
  479.     LoadMenu,
  480.     M_DrawLoad,
  481.     80,54,
  482.     0
  483. };
  484.  
  485. //
  486. // SAVE GAME MENU
  487. //
  488. menuitem_t SaveMenu[]=
  489. {
  490.     {1,"", M_SaveSelect,'1'},
  491.     {1,"", M_SaveSelect,'2'},
  492.     {1,"", M_SaveSelect,'3'},
  493.     {1,"", M_SaveSelect,'4'},
  494.     {1,"", M_SaveSelect,'5'},
  495.     {1,"", M_SaveSelect,'6'}
  496. };
  497.  
  498. menu_t  SaveDef =
  499. {
  500.     load_end,
  501.     &MainDef,
  502.     SaveMenu,
  503.     M_DrawSave,
  504.     80,54,
  505.     0
  506. };
  507.  
  508.  
  509. //
  510. // M_ReadSaveStrings
  511. //  read the strings from the savegame files
  512. //
  513. void M_ReadSaveStrings(void)
  514. {
  515. #ifdef __VBCC__
  516.         FILE                        *handle;
  517. #else
  518.     int             handle;
  519. #endif
  520.     int             count;
  521.     int             i;
  522.     char    name[256];
  523.     
  524.     for (i = 0;i < load_end;i++)
  525.     {
  526.     if (M_CheckParm("-cdrom"))
  527.         sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",i);
  528.     else
  529.         sprintf(name,SAVEGAMENAME"%d.dsg",i);
  530.  
  531. #ifdef __VBCC__
  532.     handle = fopen(name, "rb");
  533.     if (handle == NULL)
  534.     {
  535.         strcpy(&savegamestrings[i][0],EMPTYSTRING);
  536.         LoadMenu[i].status = 0;
  537.         continue;
  538.     }
  539.     count = fread(&savegamestrings[i], 1, SAVESTRINGSIZE, handle);
  540.     fclose(handle);
  541. #else
  542.     handle = open (name, O_RDONLY | 0, 0666);
  543.     if (handle == -1)
  544.     {
  545.         strcpy(&savegamestrings[i][0],EMPTYSTRING);
  546.         LoadMenu[i].status = 0;
  547.         continue;
  548.     }
  549.     count = read (handle, &savegamestrings[i], SAVESTRINGSIZE);
  550.     close (handle);
  551. #endif
  552.     LoadMenu[i].status = 1;
  553.     }
  554. }
  555.  
  556.  
  557. //
  558. // M_LoadGame & Cie.
  559. //
  560. void M_DrawLoad(void)
  561. {
  562.     int             i;
  563.     
  564.     V_DrawPatchInDirect (72,28,0,W_CacheLumpName("M_LOADG",PU_CACHE));
  565.     for (i = 0;i < load_end; i++)
  566.     {
  567.     M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
  568.     M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
  569.     }
  570. }
  571.  
  572.  
  573.  
  574. //
  575. // Draw border for the savegame description
  576. //
  577. void M_DrawSaveLoadBorder(int x,int y)
  578. {
  579.     int             i;
  580.     
  581.     V_DrawPatchInDirect (x-8,y+7,0,W_CacheLumpName("M_LSLEFT",PU_CACHE));
  582.     
  583.     for (i = 0;i < 24;i++)
  584.     {
  585.     V_DrawPatchInDirect (x,y+7,0,W_CacheLumpName("M_LSCNTR",PU_CACHE));
  586.     x += 8;
  587.     }
  588.  
  589.     V_DrawPatchInDirect (x,y+7,0,W_CacheLumpName("M_LSRGHT",PU_CACHE));
  590. }
  591.  
  592.  
  593.  
  594. //
  595. // User wants to load this game
  596. //
  597. void M_LoadSelect(int choice)
  598. {
  599.     char    name[256];
  600.     
  601.     if (M_CheckParm("-cdrom"))
  602.     sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",choice);
  603.     else
  604.     sprintf(name,SAVEGAMENAME"%d.dsg",choice);
  605.     G_LoadGame (name);
  606.     M_ClearMenus ();
  607. }
  608.  
  609. //
  610. // Selected from DOOM menu
  611. //
  612. void M_LoadGame (int choice)
  613. {
  614.     if (netgame)
  615.     {
  616.     M_StartMessage(LOADNET,NULL,false);
  617.     return;
  618.     }
  619.     
  620.     M_SetupNextMenu(&LoadDef);
  621.     M_ReadSaveStrings();
  622. }
  623.  
  624.  
  625. //
  626. //  M_SaveGame & Cie.
  627. //
  628. void M_DrawSave(void)
  629. {
  630.     int             i;
  631.     
  632.     V_DrawPatchInDirect (72,28,0,W_CacheLumpName("M_SAVEG",PU_CACHE));
  633.     for (i = 0;i < load_end; i++)
  634.     {
  635.     M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i);
  636.     M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
  637.     }
  638.     
  639.     if (saveStringEnter)
  640.     {
  641.     i = M_StringWidth(savegamestrings[saveSlot]);
  642.     M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
  643.     }
  644. }
  645.  
  646. //
  647. // M_Responder calls this when user is finished
  648. //
  649. void M_DoSave(int slot)
  650. {
  651.     G_SaveGame (slot,savegamestrings[slot]);
  652.     M_ClearMenus ();
  653.  
  654.     // PICK QUICKSAVE SLOT YET?
  655.     if (quickSaveSlot == -2)
  656.     quickSaveSlot = slot;
  657. }
  658.  
  659. //
  660. // User wants to save. Start string input for M_Responder
  661. //
  662. void M_SaveSelect(int choice)
  663. {
  664.     // we are going to be intercepting all chars
  665.     saveStringEnter = 1;
  666.     
  667.     saveSlot = choice;
  668.     strcpy(saveOldString,savegamestrings[choice]);
  669.     if (!strcmp(savegamestrings[choice],EMPTYSTRING))
  670.     savegamestrings[choice][0] = 0;
  671.     saveCharIndex = strlen(savegamestrings[choice]);
  672. }
  673.  
  674. //
  675. // Selected from DOOM menu
  676. //
  677. void M_SaveGame (int choice)
  678. {
  679.     if (!usergame)
  680.     {
  681.     M_StartMessage(SAVEDEAD,NULL,false);
  682.     return;
  683.     }
  684.     
  685.     if (gamestate != GS_LEVEL)
  686.     return;
  687.     
  688.     M_SetupNextMenu(&SaveDef);
  689.     M_ReadSaveStrings();
  690. }
  691.  
  692.  
  693.  
  694. //
  695. //      M_QuickSave
  696. //
  697. char    tempstring[80];
  698.  
  699. void M_QuickSaveResponse(int ch)
  700. {
  701.     if (ch == 'y')
  702.     {
  703.     M_DoSave(quickSaveSlot);
  704.     S_StartSound(NULL,sfx_swtchx);
  705.     }
  706. }
  707.  
  708. void M_QuickSave(void)
  709. {
  710.     if (!usergame)
  711.     {
  712.     S_StartSound(NULL,sfx_oof);
  713.     return;
  714.     }
  715.  
  716.     if (gamestate != GS_LEVEL)
  717.     return;
  718.     
  719.     if (quickSaveSlot < 0)
  720.     {
  721.     M_StartControlPanel();
  722.     M_ReadSaveStrings();
  723.     M_SetupNextMenu(&SaveDef);
  724.     quickSaveSlot = -2;    // means to pick a slot now
  725.     return;
  726.     }
  727.     sprintf(tempstring,QSPROMPT,savegamestrings[quickSaveSlot]);
  728.     M_StartMessage(tempstring,M_QuickSaveResponse,true);
  729. }
  730.  
  731.  
  732.  
  733. //
  734. // M_QuickLoad
  735. //
  736. void M_QuickLoadResponse(int ch)
  737. {
  738.     if (ch == 'y')
  739.     {
  740.     M_LoadSelect(quickSaveSlot);
  741.     S_StartSound(NULL,sfx_swtchx);
  742.     }
  743. }
  744.  
  745.  
  746. void M_QuickLoad(void)
  747. {
  748.     if (netgame)
  749.     {
  750.     M_StartMessage(QLOADNET,NULL,false);
  751.     return;
  752.     }
  753.     
  754.     if (quickSaveSlot < 0)
  755.     {
  756.     M_StartMessage(QSAVESPOT,NULL,false);
  757.     return;
  758.     }
  759.     sprintf(tempstring,QLPROMPT,savegamestrings[quickSaveSlot]);
  760.     M_StartMessage(tempstring,M_QuickLoadResponse,true);
  761. }
  762.  
  763.  
  764.  
  765.  
  766. //
  767. // Read This Menus
  768. // Had a "quick hack to fix romero bug"
  769. //
  770. void M_DrawReadThis1(void)
  771. {
  772.     inhelpscreens = true;
  773.     switch ( gamemode )
  774.     {
  775.       case commercial:
  776.     V_DrawPatchInDirect (0,0,0,W_CacheLumpName("HELP",PU_CACHE));
  777.     break;
  778.       case shareware:
  779.       case registered:
  780.       case retail:
  781.     V_DrawPatchInDirect (0,0,0,W_CacheLumpName("HELP1",PU_CACHE));
  782.     break;
  783.       default:
  784.     break;
  785.     }
  786.     return;
  787. }
  788.  
  789.  
  790.  
  791. //
  792. // Read This Menus - optional second page.
  793. //
  794. void M_DrawReadThis2(void)
  795. {
  796.     inhelpscreens = true;
  797.     switch ( gamemode )
  798.     {
  799.       case retail:
  800.       case commercial:
  801.     // This hack keeps us from having to change menus.
  802.     V_DrawPatchInDirect (0,0,0,W_CacheLumpName("CREDIT",PU_CACHE));
  803.     break;
  804.       case shareware:
  805.       case registered:
  806.     V_DrawPatchInDirect (0,0,0,W_CacheLumpName("HELP2",PU_CACHE));
  807.     break;
  808.       default:
  809.     break;
  810.     }
  811.     return;
  812. }
  813.  
  814.  
  815. //
  816. // Change Sfx & Music volumes
  817. //
  818. void M_DrawSound(void)
  819. {
  820.     V_DrawPatchInDirect (60,38,0,W_CacheLumpName("M_SVOL",PU_CACHE));
  821.  
  822.     M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
  823.          16,snd_SfxVolume);
  824.  
  825.     M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
  826.          16,snd_MusicVolume);
  827. }
  828.  
  829. void M_Sound(int choice)
  830. {
  831.     M_SetupNextMenu(&SoundDef);
  832. }
  833.  
  834. void M_SfxVol(int choice)
  835. {
  836.     switch(choice)
  837.     {
  838.       case 0:
  839.     if (snd_SfxVolume)
  840.         snd_SfxVolume--;
  841.     break;
  842.       case 1:
  843.     if (snd_SfxVolume < 15)
  844.         snd_SfxVolume++;
  845.     break;
  846.     }
  847.     
  848.     S_SetSfxVolume(snd_SfxVolume /* *8 */);
  849. }
  850.  
  851. void M_MusicVol(int choice)
  852. {
  853.     switch(choice)
  854.     {
  855.       case 0:
  856.     if (snd_MusicVolume)
  857.         snd_MusicVolume--;
  858.     break;
  859.       case 1:
  860.     if (snd_MusicVolume < 15)
  861.         snd_MusicVolume++;
  862.     break;
  863.     }
  864.     
  865.     S_SetMusicVolume(snd_MusicVolume /* *8 */);
  866. }
  867.  
  868.  
  869.  
  870.  
  871. //
  872. // M_DrawMainMenu
  873. //
  874. void M_DrawMainMenu(void)
  875. {
  876.     V_DrawPatchInDirect (94,2,0,W_CacheLumpName("M_DOOM",PU_CACHE));
  877. }
  878.  
  879.  
  880.  
  881.  
  882. //
  883. // M_NewGame
  884. //
  885. void M_DrawNewGame(void)
  886. {
  887.     V_DrawPatchInDirect (96,14,0,W_CacheLumpName("M_NEWG",PU_CACHE));
  888.     V_DrawPatchInDirect (54,38,0,W_CacheLumpName("M_SKILL",PU_CACHE));
  889. }
  890.  
  891. void M_NewGame(int choice)
  892. {
  893.     if (netgame && !demoplayback)
  894.     {
  895.     M_StartMessage(NEWGAME,NULL,false);
  896.     return;
  897.     }
  898.     
  899.     if ( gamemode == commercial )
  900.     M_SetupNextMenu(&NewDef);
  901.     else
  902.     M_SetupNextMenu(&EpiDef);
  903. }
  904.  
  905.  
  906. //
  907. //      M_Episode
  908. //
  909. int     epi;
  910.  
  911. void M_DrawEpisode(void)
  912. {
  913.     V_DrawPatchInDirect (54,38,0,W_CacheLumpName("M_EPISOD",PU_CACHE));
  914. }
  915.  
  916. void M_VerifyNightmare(int ch)
  917. {
  918.     if (ch != 'y')
  919.     return;
  920.         
  921.     G_DeferedInitNew(nightmare,epi+1,1);
  922.     M_ClearMenus ();
  923. }
  924.  
  925. void M_ChooseSkill(int choice)
  926. {
  927.     if (choice == nightmare)
  928.     {
  929.     M_StartMessage(NIGHTMARE,M_VerifyNightmare,true);
  930.     return;
  931.     }
  932.     
  933.     G_DeferedInitNew(choice,epi+1,1);
  934.     M_ClearMenus ();
  935. }
  936.  
  937. void M_Episode(int choice)
  938. {
  939.     if ( (gamemode == shareware)
  940.      && choice)
  941.     {
  942.     M_StartMessage(SWSTRING,NULL,false);
  943.     M_SetupNextMenu(&ReadDef1);
  944.     return;
  945.     }
  946.  
  947.     // Yet another hack...
  948.     if ( (gamemode == registered)
  949.      && (choice > 2))
  950.     {
  951.       fprintf( stderr,
  952.            "M_Episode: 4th episode requires UltimateDOOM\n");
  953.       choice = 0;
  954.     }
  955.      
  956.     epi = choice;
  957.     M_SetupNextMenu(&NewDef);
  958. }
  959.  
  960.  
  961.  
  962. //
  963. // M_Options
  964. //
  965. char    detailNames[2][9]    = {"M_GDHIGH","M_GDLOW"};
  966. char    msgNames[2][9]        = {"M_MSGOFF","M_MSGON"};
  967.  
  968.  
  969. void M_DrawOptions(void)
  970. {
  971.     V_DrawPatchInDirect (108,15,0,W_CacheLumpName("M_OPTTTL",PU_CACHE));
  972.     
  973.     V_DrawPatchInDirect (OptionsDef.x + 175,OptionsDef.y+LINEHEIGHT*detail,0,
  974.                W_CacheLumpName(detailNames[detailLevel],PU_CACHE));
  975.  
  976.     V_DrawPatchInDirect (OptionsDef.x + 120,OptionsDef.y+LINEHEIGHT*messages,0,
  977.                W_CacheLumpName(msgNames[showMessages],PU_CACHE));
  978.  
  979.     M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(mousesens+1),
  980.          10,mouseSensitivity);
  981.     
  982.     M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
  983.          9,screenSize);
  984. }
  985.  
  986. void M_Options(int choice)
  987. {
  988.     M_SetupNextMenu(&OptionsDef);
  989. }
  990.  
  991.  
  992.  
  993. //
  994. //      Toggle messages on/off
  995. //
  996. void M_ChangeMessages(int choice)
  997. {
  998.     // warning: unused parameter `int choice'
  999.     choice = 0;
  1000.     showMessages = 1 - showMessages;
  1001.     
  1002.     if (!showMessages)
  1003.     players[consoleplayer].message = MSGOFF;
  1004.     else
  1005.     players[consoleplayer].message = MSGON ;
  1006.  
  1007.     message_dontfuckwithme = true;
  1008. }
  1009.  
  1010.  
  1011. //
  1012. // M_EndGame
  1013. //
  1014. void M_EndGameResponse(int ch)
  1015. {
  1016.     if (ch != 'y')
  1017.     return;
  1018.         
  1019.     currentMenu->lastOn = itemOn;
  1020.     M_ClearMenus ();
  1021.     D_StartTitle ();
  1022. }
  1023.  
  1024. void M_EndGame(int choice)
  1025. {
  1026.     choice = 0;
  1027.     if (!usergame)
  1028.     {
  1029.     S_StartSound(NULL,sfx_oof);
  1030.     return;
  1031.     }
  1032.     
  1033.     if (netgame)
  1034.     {
  1035.     M_StartMessage(NETEND,NULL,false);
  1036.     return;
  1037.     }
  1038.     
  1039.     M_StartMessage(ENDGAME,M_EndGameResponse,true);
  1040. }
  1041.  
  1042.  
  1043.  
  1044.  
  1045. //
  1046. // M_ReadThis
  1047. //
  1048. void M_ReadThis(int choice)
  1049. {
  1050.     choice = 0;
  1051.     M_SetupNextMenu(&ReadDef1);
  1052. }
  1053.  
  1054. void M_ReadThis2(int choice)
  1055. {
  1056.     choice = 0;
  1057.     M_SetupNextMenu(&ReadDef2);
  1058. }
  1059.  
  1060. void M_FinishReadThis(int choice)
  1061. {
  1062.     choice = 0;
  1063.     M_SetupNextMenu(&MainDef);
  1064. }
  1065.  
  1066.  
  1067.  
  1068.  
  1069. //
  1070. // M_QuitDOOM
  1071. //
  1072. int     quitsounds[8] =
  1073. {
  1074.     sfx_pldeth,
  1075.     sfx_dmpain,
  1076.     sfx_popain,
  1077.     sfx_slop,
  1078.     sfx_telept,
  1079.     sfx_posit1,
  1080.     sfx_posit3,
  1081.     sfx_sgtatk
  1082. };
  1083.  
  1084. int     quitsounds2[8] =
  1085. {
  1086.     sfx_vilact,
  1087.     sfx_getpow,
  1088.     sfx_boscub,
  1089.     sfx_slop,
  1090.     sfx_skeswg,
  1091.     sfx_kntdth,
  1092.     sfx_bspact,
  1093.     sfx_sgtatk
  1094. };
  1095.  
  1096.  
  1097.  
  1098. void M_QuitResponse(int ch)
  1099. {
  1100.     if (ch != 'y')
  1101.     return;
  1102.     if (!netgame)
  1103.     {
  1104.     if (gamemode == commercial)
  1105.         S_StartSound(NULL,quitsounds2[(gametic>>2)&7]);
  1106.     else
  1107.         S_StartSound(NULL,quitsounds[(gametic>>2)&7]);
  1108.     I_WaitVBL(105);
  1109.     }
  1110.     I_Quit ();
  1111. }
  1112.  
  1113.  
  1114.  
  1115.  
  1116. void M_QuitDOOM(int choice)
  1117. {
  1118.   // We pick index 0 which is language sensitive,
  1119.   //  or one at random, between 1 and maximum number.
  1120.   if (language != english )
  1121.     sprintf(endstring,"%s\n\n"DOSY, endmsg[0] );
  1122.   else
  1123.     sprintf(endstring,"%s\n\n"DOSY, endmsg[ (gametic%(NUM_QUITMESSAGES-2))+1 ]);
  1124.   
  1125.   M_StartMessage(endstring,M_QuitResponse,true);
  1126. }
  1127.  
  1128.  
  1129.  
  1130.  
  1131. void M_ChangeSensitivity(int choice)
  1132. {
  1133.     switch(choice)
  1134.     {
  1135.       case 0:
  1136.     if (mouseSensitivity)
  1137.         mouseSensitivity--;
  1138.     break;
  1139.       case 1:
  1140.     if (mouseSensitivity < 9)
  1141.         mouseSensitivity++;
  1142.     break;
  1143.     }
  1144. }
  1145.  
  1146.  
  1147.  
  1148.  
  1149. void M_ChangeDetail(int choice)
  1150. {
  1151.     choice = 0;
  1152.     detailLevel = 1 - detailLevel;
  1153.  
  1154.     // FIXME - does not work. Remove anyway?
  1155. //    fprintf( stderr, "M_ChangeDetail: low detail mode n.a.\n");
  1156.  
  1157. //    return;
  1158.     
  1159.     R_SetViewSize (screenblocks, detailLevel);
  1160.  
  1161.     if (!detailLevel)
  1162.     players[consoleplayer].message = DETAILHI;
  1163.     else
  1164.     players[consoleplayer].message = DETAILLO;
  1165. }
  1166.  
  1167.  
  1168.  
  1169.  
  1170. void M_SizeDisplay(int choice)
  1171. {
  1172.     switch(choice)
  1173.     {
  1174.       case 0:
  1175.     if (screenSize > 0)
  1176.     {
  1177.         screenblocks--;
  1178.         screenSize--;
  1179.     }
  1180.     break;
  1181.       case 1:
  1182.     if (screenSize < 8)
  1183.     {
  1184.         screenblocks++;
  1185.         screenSize++;
  1186.     }
  1187.     break;
  1188.     }
  1189.     
  1190.  
  1191.     R_SetViewSize (screenblocks, detailLevel);
  1192. }
  1193.  
  1194.  
  1195.  
  1196.  
  1197. //
  1198. //      Menu Functions
  1199. //
  1200. void
  1201. M_DrawThermo
  1202. ( int    x,
  1203.   int    y,
  1204.   int    thermWidth,
  1205.   int    thermDot )
  1206. {
  1207.     int        xx;
  1208.     int        i;
  1209.  
  1210.     xx = x;
  1211.     V_DrawPatchInDirect (xx,y,0,W_CacheLumpName("M_THERML",PU_CACHE));
  1212.     xx += 8;
  1213.     for (i=0;i<thermWidth;i++)
  1214.     {
  1215.     V_DrawPatchInDirect (xx,y,0,W_CacheLumpName("M_THERMM",PU_CACHE));
  1216.     xx += 8;
  1217.     }
  1218.     V_DrawPatchInDirect (xx,y,0,W_CacheLumpName("M_THERMR",PU_CACHE));
  1219.  
  1220.     V_DrawPatchInDirect ((x+8) + thermDot*8,y,
  1221.                0,W_CacheLumpName("M_THERMO",PU_CACHE));
  1222. }
  1223.  
  1224.  
  1225.  
  1226. void
  1227. M_DrawEmptyCell
  1228. ( menu_t*    menu,
  1229.   int        item )
  1230. {
  1231.     V_DrawPatchInDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
  1232.                W_CacheLumpName("M_CELL1",PU_CACHE));
  1233. }
  1234.  
  1235. void
  1236. M_DrawSelCell
  1237. ( menu_t*    menu,
  1238.   int        item )
  1239. {
  1240.     V_DrawPatchInDirect (menu->x - 10,        menu->y+item*LINEHEIGHT - 1, 0,
  1241.                W_CacheLumpName("M_CELL2",PU_CACHE));
  1242. }
  1243.  
  1244.  
  1245. void
  1246. M_StartMessage
  1247. ( char*        string,
  1248.   void          (*routine)(int response),
  1249. /*  void*        routine, */
  1250.   boolean    input )
  1251. {
  1252.     messageLastMenuActive = menuactive;
  1253.     messageToPrint = 1;
  1254.     messageString = string;
  1255.     messageRoutine = routine;
  1256.     messageNeedsInput = input;
  1257.     menuactive = true;
  1258.     return;
  1259. }
  1260.  
  1261.  
  1262.  
  1263. void M_StopMessage(void)
  1264. {
  1265.     menuactive = messageLastMenuActive;
  1266.     messageToPrint = 0;
  1267. }
  1268.  
  1269.  
  1270.  
  1271. //
  1272. // Find string width from hu_font chars
  1273. //
  1274. int M_StringWidth(char* string)
  1275. {
  1276.     int             i;
  1277.     int             w = 0;
  1278.     int             c;
  1279.     
  1280.     for (i = 0;i < strlen(string);i++)
  1281.     {
  1282.     c = toupper(string[i]) - HU_FONTSTART;
  1283.     if (c < 0 || c >= HU_FONTSIZE)
  1284.         w += 4;
  1285.     else
  1286.         w += SWAPSHORT(hu_font[c]->width);
  1287.     }
  1288.         
  1289.     return w;
  1290. }
  1291.  
  1292.  
  1293.  
  1294. //
  1295. //      Find string height from hu_font chars
  1296. //
  1297. int M_StringHeight(char* string)
  1298. {
  1299.     int             i;
  1300.     int             h;
  1301.     int             height = SWAPSHORT(hu_font[0]->height);
  1302.     
  1303.     h = height;
  1304.     for (i = 0;i < strlen(string);i++)
  1305.     if (string[i] == '\n')
  1306.         h += height;
  1307.         
  1308.     return h;
  1309. }
  1310.  
  1311.  
  1312. //
  1313. //      Write a string using the hu_font
  1314. //
  1315. void
  1316. M_WriteText
  1317. ( int        x,
  1318.   int        y,
  1319.   char*        string)
  1320. {
  1321.     int        w;
  1322.     char*    ch;
  1323.     int        c;
  1324.     int        cx;
  1325.     int        cy;
  1326.         
  1327.  
  1328.     ch = string;
  1329.     cx = x;
  1330.     cy = y;
  1331.     
  1332.     while(1)
  1333.     {
  1334.     c = *ch++;
  1335.     if (!c)
  1336.         break;
  1337.     if (c == '\n')
  1338.     {
  1339.         cx = x;
  1340.         cy += 12;
  1341.         continue;
  1342.     }
  1343.         
  1344.     c = toupper(c) - HU_FONTSTART;
  1345.     if (c < 0 || c>= HU_FONTSIZE)
  1346.     {
  1347.         cx += 4;
  1348.         continue;
  1349.     }
  1350.         
  1351.     w = SWAPSHORT(hu_font[c]->width);
  1352.     if (cx+w > SCREENWIDTH)
  1353.         break;
  1354.     V_DrawPatchInDirect(cx, cy, 0, hu_font[c]);
  1355.     cx+=w;
  1356.     }
  1357. }
  1358.  
  1359.  
  1360.  
  1361. //
  1362. // CONTROL PANEL
  1363. //
  1364.  
  1365. //
  1366. // M_Responder
  1367. //
  1368. boolean M_Responder (event_t* ev)
  1369. {
  1370.     int             ch;
  1371.     int             i;
  1372.     static  int     joywait = 0;
  1373.     static  int     mousewait = 0;
  1374.     static  int     mousey = 0;
  1375.     static  int     lasty = 0;
  1376.     static  int     mousex = 0;
  1377.     static  int     lastx = 0;
  1378.     
  1379.     ch = -1;
  1380.     
  1381.     if (ev->type == ev_joystick && joywait < I_GetTime())
  1382.     {
  1383.     if (ev->data3 == -1)
  1384.     {
  1385.         ch = KEY_UPARROW;
  1386.         joywait = I_GetTime() + 5;
  1387.     }
  1388.     else if (ev->data3 == 1)
  1389.     {
  1390.         ch = KEY_DOWNARROW;
  1391.         joywait = I_GetTime() + 5;
  1392.     }
  1393.         
  1394.     if (ev->data2 == -1)
  1395.     {
  1396.         ch = KEY_LEFTARROW;
  1397.         joywait = I_GetTime() + 2;
  1398.     }
  1399.     else if (ev->data2 == 1)
  1400.     {
  1401.         ch = KEY_RIGHTARROW;
  1402.         joywait = I_GetTime() + 2;
  1403.     }
  1404.         
  1405.     if (ev->data1&1)
  1406.     {
  1407.         ch = KEY_ENTER;
  1408.         joywait = I_GetTime() + 5;
  1409.     }
  1410.     if (ev->data1&2)
  1411.     {
  1412.         ch = KEY_BACKSPACE;
  1413.         joywait = I_GetTime() + 5;
  1414.     }
  1415.     }
  1416.     else
  1417.     {
  1418.     if (ev->type == ev_mouse && mousewait < I_GetTime())
  1419.     {
  1420.         mousey += ev->data3;
  1421.         if (mousey < lasty-30)
  1422.         {
  1423.         ch = KEY_DOWNARROW;
  1424.         mousewait = I_GetTime() + 5;
  1425.         mousey = lasty -= 30;
  1426.         }
  1427.         else if (mousey > lasty+30)
  1428.         {
  1429.         ch = KEY_UPARROW;
  1430.         mousewait = I_GetTime() + 5;
  1431.         mousey = lasty += 30;
  1432.         }
  1433.         
  1434.         mousex += ev->data2;
  1435.         if (mousex < lastx-30)
  1436.         {
  1437.         ch = KEY_LEFTARROW;
  1438.         mousewait = I_GetTime() + 5;
  1439.         mousex = lastx -= 30;
  1440.         }
  1441.         else if (mousex > lastx+30)
  1442.         {
  1443.         ch = KEY_RIGHTARROW;
  1444.         mousewait = I_GetTime() + 5;
  1445.         mousex = lastx += 30;
  1446.         }
  1447.         
  1448.         if (ev->data1&1)
  1449.         {
  1450.         ch = KEY_ENTER;
  1451.         mousewait = I_GetTime() + 15;
  1452.         }
  1453.             
  1454.         if (ev->data1&2)
  1455.         {
  1456.         ch = KEY_BACKSPACE;
  1457.         mousewait = I_GetTime() + 15;
  1458.         }
  1459.     }
  1460.     else
  1461.         if (ev->type == ev_keydown)
  1462.         {
  1463.         ch = ev->data1;
  1464.         }
  1465.     }
  1466.     
  1467.     if (ch == -1)
  1468.     return false;
  1469.  
  1470.     
  1471.     // Save Game string input
  1472.     if (saveStringEnter)
  1473.     {
  1474.     switch(ch)
  1475.     {
  1476.       case KEY_BACKSPACE:
  1477.         if (saveCharIndex > 0)
  1478.         {
  1479.         saveCharIndex--;
  1480.         savegamestrings[saveSlot][saveCharIndex] = 0;
  1481.         }
  1482.         break;
  1483.                 
  1484.       case KEY_ESCAPE:
  1485.         saveStringEnter = 0;
  1486.         strcpy(&savegamestrings[saveSlot][0],saveOldString);
  1487.         break;
  1488.                 
  1489.       case KEY_ENTER:
  1490.         saveStringEnter = 0;
  1491.         if (savegamestrings[saveSlot][0])
  1492.         M_DoSave(saveSlot);
  1493.         break;
  1494.                 
  1495.       default:
  1496.         ch = toupper(ch);
  1497.         if (ch != 32)
  1498.         if (ch-HU_FONTSTART < 0 || ch-HU_FONTSTART >= HU_FONTSIZE)
  1499.             break;
  1500.         if (ch >= 32 && ch <= 127 &&
  1501.         saveCharIndex < SAVESTRINGSIZE-1 &&
  1502.         M_StringWidth(savegamestrings[saveSlot]) <
  1503.         (SAVESTRINGSIZE-2)*8)
  1504.         {
  1505.         savegamestrings[saveSlot][saveCharIndex++] = ch;
  1506.         savegamestrings[saveSlot][saveCharIndex] = 0;
  1507.         }
  1508.         break;
  1509.     }
  1510.     return true;
  1511.     }
  1512.     
  1513.     // Take care of any messages that need input
  1514.     if (messageToPrint)
  1515.     {
  1516.     if (messageNeedsInput == true &&
  1517.         !(ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE))
  1518.         return false;
  1519.         
  1520.     menuactive = messageLastMenuActive;
  1521.     messageToPrint = 0;
  1522.     if (messageRoutine)
  1523.         messageRoutine(ch);
  1524.             
  1525.     menuactive = false;
  1526.     S_StartSound(NULL,sfx_swtchx);
  1527.     return true;
  1528.     }
  1529.     
  1530.     if (devparm && ch == KEY_F1)
  1531.     {
  1532.     G_ScreenShot ();
  1533.     return true;
  1534.     }
  1535.         
  1536.     
  1537.     // F-Keys
  1538.     if (!menuactive)
  1539.     switch(ch)
  1540.     {
  1541.       case KEY_MINUS:         // Screen size down
  1542.         if (automapactive || chat_on)
  1543.         return false;
  1544.         M_SizeDisplay(0);
  1545.         S_StartSound(NULL,sfx_stnmov);
  1546.         return true;
  1547.                 
  1548.       case KEY_EQUALS:        // Screen size up
  1549.         if (automapactive || chat_on)
  1550.         return false;
  1551.         M_SizeDisplay(1);
  1552.         S_StartSound(NULL,sfx_stnmov);
  1553.         return true;
  1554.                 
  1555.       case KEY_F1:            // Help key
  1556.         M_StartControlPanel ();
  1557.  
  1558.         if ( gamemode == retail )
  1559.           currentMenu = &ReadDef2;
  1560.         else
  1561.           currentMenu = &ReadDef1;
  1562.         
  1563.         itemOn = 0;
  1564.         S_StartSound(NULL,sfx_swtchn);
  1565.         return true;
  1566.                 
  1567.       case KEY_F2:            // Save
  1568.         M_StartControlPanel();
  1569.         S_StartSound(NULL,sfx_swtchn);
  1570.         M_SaveGame(0);
  1571.         return true;
  1572.                 
  1573.       case KEY_F3:            // Load
  1574.         M_StartControlPanel();
  1575.         S_StartSound(NULL,sfx_swtchn);
  1576.         M_LoadGame(0);
  1577.         return true;
  1578.                 
  1579.       case KEY_F4:            // Sound Volume
  1580.         M_StartControlPanel ();
  1581.         currentMenu = &SoundDef;
  1582.         itemOn = sfx_vol;
  1583.         S_StartSound(NULL,sfx_swtchn);
  1584.         return true;
  1585.                 
  1586.       case KEY_F5:            // Detail toggle
  1587.         M_ChangeDetail(0);
  1588.         S_StartSound(NULL,sfx_swtchn);
  1589.         return true;
  1590.                 
  1591.       case KEY_F6:            // Quicksave
  1592.         S_StartSound(NULL,sfx_swtchn);
  1593.         M_QuickSave();
  1594.         return true;
  1595.                 
  1596.       case KEY_F7:            // End game
  1597.         S_StartSound(NULL,sfx_swtchn);
  1598.         M_EndGame(0);
  1599.         return true;
  1600.                 
  1601.       case KEY_F8:            // Toggle messages
  1602.         M_ChangeMessages(0);
  1603.         S_StartSound(NULL,sfx_swtchn);
  1604.         return true;
  1605.                 
  1606.       case KEY_F9:            // Quickload
  1607.         S_StartSound(NULL,sfx_swtchn);
  1608.         M_QuickLoad();
  1609.         return true;
  1610.                 
  1611.       case KEY_F10:           // Quit DOOM
  1612.         S_StartSound(NULL,sfx_swtchn);
  1613.         M_QuitDOOM(0);
  1614.         return true;
  1615.                 
  1616.       case KEY_F11:           // gamma toggle
  1617.         usegamma++;
  1618.         if (usegamma > 4)
  1619.         usegamma = 0;
  1620.         players[consoleplayer].message = gammamsg[usegamma];
  1621.         I_RecalcPalettes ();
  1622.         I_SetPalette (W_CacheLumpName ("PLAYPAL",PU_CACHE), 0);
  1623.         return true;
  1624.                 
  1625.     }
  1626.  
  1627.     
  1628.     // Pop-up menu?
  1629.     if (!menuactive)
  1630.     {
  1631.     if (ch == KEY_ESCAPE)
  1632.     {
  1633.         M_StartControlPanel ();
  1634.         S_StartSound(NULL,sfx_swtchn);
  1635.         return true;
  1636.     }
  1637.     return false;
  1638.     }
  1639.  
  1640.     
  1641.     // Keys usable within menu
  1642.     switch (ch)
  1643.     {
  1644.       case KEY_DOWNARROW:
  1645.     do
  1646.     {
  1647.         if (itemOn+1 > currentMenu->numitems-1)
  1648.         itemOn = 0;
  1649.         else itemOn++;
  1650.         S_StartSound(NULL,sfx_pstop);
  1651.     } while(currentMenu->menuitems[itemOn].status==-1);
  1652.     return true;
  1653.         
  1654.       case KEY_UPARROW:
  1655.     do
  1656.     {
  1657.         if (!itemOn)
  1658.         itemOn = currentMenu->numitems-1;
  1659.         else itemOn--;
  1660.         S_StartSound(NULL,sfx_pstop);
  1661.     } while(currentMenu->menuitems[itemOn].status==-1);
  1662.     return true;
  1663.  
  1664.       case KEY_LEFTARROW:
  1665.     if (currentMenu->menuitems[itemOn].routine &&
  1666.         currentMenu->menuitems[itemOn].status == 2)
  1667.     {
  1668.         S_StartSound(NULL,sfx_stnmov);
  1669.         currentMenu->menuitems[itemOn].routine(0);
  1670.     }
  1671.     return true;
  1672.         
  1673.       case KEY_RIGHTARROW:
  1674.     if (currentMenu->menuitems[itemOn].routine &&
  1675.         currentMenu->menuitems[itemOn].status == 2)
  1676.     {
  1677.         S_StartSound(NULL,sfx_stnmov);
  1678.         currentMenu->menuitems[itemOn].routine(1);
  1679.     }
  1680.     return true;
  1681.  
  1682.       case KEY_ENTER:
  1683.     if (currentMenu->menuitems[itemOn].routine &&
  1684.         currentMenu->menuitems[itemOn].status)
  1685.     {
  1686.         currentMenu->lastOn = itemOn;
  1687.         if (currentMenu->menuitems[itemOn].status == 2)
  1688.         {
  1689.         currentMenu->menuitems[itemOn].routine(1);      // right arrow
  1690.         S_StartSound(NULL,sfx_stnmov);
  1691.         }
  1692.         else
  1693.         {
  1694.         currentMenu->menuitems[itemOn].routine(itemOn);
  1695.         S_StartSound(NULL,sfx_pistol);
  1696.         }
  1697.     }
  1698.     return true;
  1699.         
  1700.       case KEY_ESCAPE:
  1701.     currentMenu->lastOn = itemOn;
  1702.     M_ClearMenus ();
  1703.     S_StartSound(NULL,sfx_swtchx);
  1704.     return true;
  1705.         
  1706.       case KEY_BACKSPACE:
  1707.     currentMenu->lastOn = itemOn;
  1708.     if (currentMenu->prevMenu)
  1709.     {
  1710.         currentMenu = currentMenu->prevMenu;
  1711.         itemOn = currentMenu->lastOn;
  1712.         S_StartSound(NULL,sfx_swtchn);
  1713.     }
  1714.     return true;
  1715.     
  1716.       default:
  1717.     for (i = itemOn+1;i < currentMenu->numitems;i++)
  1718.         if (currentMenu->menuitems[i].alphaKey == ch)
  1719.         {
  1720.         itemOn = i;
  1721.         S_StartSound(NULL,sfx_pstop);
  1722.         return true;
  1723.         }
  1724.     for (i = 0;i <= itemOn;i++)
  1725.         if (currentMenu->menuitems[i].alphaKey == ch)
  1726.         {
  1727.         itemOn = i;
  1728.         S_StartSound(NULL,sfx_pstop);
  1729.         return true;
  1730.         }
  1731.     break;
  1732.     
  1733.     }
  1734.  
  1735.     return false;
  1736. }
  1737.  
  1738.  
  1739.  
  1740. //
  1741. // M_StartControlPanel
  1742. //
  1743. void M_StartControlPanel (void)
  1744. {
  1745.     // intro might call this repeatedly
  1746.     if (menuactive)
  1747.     return;
  1748.     
  1749.     menuactive = 1;
  1750.     currentMenu = &MainDef;         // JDC
  1751.     itemOn = currentMenu->lastOn;   // JDC
  1752. }
  1753.  
  1754.  
  1755. //
  1756. // M_Drawer
  1757. // Called after the view has been rendered,
  1758. // but before it has been blitted.
  1759. //
  1760. void M_Drawer (void)
  1761. {
  1762.     static short    x;
  1763.     static short    y;
  1764.     short        i;
  1765.     short        max;
  1766.     char        string[40];
  1767.     int            start;
  1768.  
  1769.     inhelpscreens = false;
  1770.  
  1771.     
  1772.     // Horiz. & Vertically center string and print it.
  1773.     if (messageToPrint)
  1774.     {
  1775.     start = 0;
  1776.     y = 100 - M_StringHeight(messageString)/2;
  1777.     while(*(messageString+start))
  1778.     {
  1779.         for (i = 0;i < strlen(messageString+start);i++)
  1780.         if (*(messageString+start+i) == '\n')
  1781.         {
  1782.             memset(string,0,40);
  1783.             strncpy(string,messageString+start,i);
  1784.             start += i+1;
  1785.             break;
  1786.         }
  1787.                 
  1788.         if (i == strlen(messageString+start))
  1789.         {
  1790.         strcpy(string,messageString+start);
  1791.         start += i;
  1792.         }
  1793.                 
  1794.         x = 160 - M_StringWidth(string)/2;
  1795.         M_WriteText(x,y,string);
  1796.         y += SWAPSHORT(hu_font[0]->height);
  1797.     }
  1798.     return;
  1799.     }
  1800.  
  1801.     if (!menuactive)
  1802.     return;
  1803.  
  1804.     if (currentMenu->routine)
  1805.     currentMenu->routine();         // call Draw routine
  1806.     
  1807.     // DRAW MENU
  1808.     x = currentMenu->x;
  1809.     y = currentMenu->y;
  1810.     max = currentMenu->numitems;
  1811.  
  1812.     for (i=0;i<max;i++)
  1813.     {
  1814.     if (currentMenu->menuitems[i].name[0])
  1815.         V_DrawPatchInDirect (x,y,0,
  1816.                    W_CacheLumpName(currentMenu->menuitems[i].name ,PU_CACHE));
  1817.     y += LINEHEIGHT;
  1818.     }
  1819.  
  1820.     
  1821.     // DRAW SKULL
  1822.     V_DrawPatchInDirect(x + SKULLXOFF,currentMenu->y - 5 + itemOn*LINEHEIGHT, 0,
  1823.               W_CacheLumpName(skullName[whichSkull],PU_CACHE));
  1824.  
  1825. }
  1826.  
  1827.  
  1828. //
  1829. // M_ClearMenus
  1830. //
  1831. void M_ClearMenus (void)
  1832. {
  1833.     menuactive = 0;
  1834.     // if (!netgame && usergame && paused)
  1835.     //       sendpause = true;
  1836. }
  1837.  
  1838.  
  1839.  
  1840.  
  1841. //
  1842. // M_SetupNextMenu
  1843. //
  1844. void M_SetupNextMenu(menu_t *menudef)
  1845. {
  1846.     currentMenu = menudef;
  1847.     itemOn = currentMenu->lastOn;
  1848. }
  1849.  
  1850.  
  1851. //
  1852. // M_Ticker
  1853. //
  1854. void M_Ticker (void)
  1855. {
  1856.     if (--skullAnimCounter <= 0)
  1857.     {
  1858.     whichSkull ^= 1;
  1859.     skullAnimCounter = 8;
  1860.     }
  1861. }
  1862.  
  1863.  
  1864. //
  1865. // M_Init
  1866. //
  1867. void M_Init (void)
  1868. {
  1869.     currentMenu = &MainDef;
  1870.     menuactive = 0;
  1871.     itemOn = currentMenu->lastOn;
  1872.     whichSkull = 0;
  1873.     skullAnimCounter = 10;
  1874.     screenSize = screenblocks - 3;
  1875.     messageToPrint = 0;
  1876.     messageString = NULL;
  1877.     messageLastMenuActive = menuactive;
  1878.     quickSaveSlot = -1;
  1879.  
  1880.     // Here we could catch other version dependencies,
  1881.     //  like HELP1/2, and four episodes.
  1882.  
  1883.   
  1884.     switch ( gamemode )
  1885.     {
  1886.       case commercial:
  1887.     // This is used because DOOM 2 had only one HELP
  1888.         //  page. I use CREDIT as second page now, but
  1889.     //  kept this hack for educational purposes.
  1890.     MainMenu[readthis] = MainMenu[quitdoom];
  1891.     MainDef.numitems--;
  1892.     MainDef.y += 8;
  1893.     NewDef.prevMenu = &MainDef;
  1894.     ReadDef1.routine = M_DrawReadThis1;
  1895.     ReadDef1.x = 330;
  1896.     ReadDef1.y = 165;
  1897.     ReadMenu1[0].routine = M_FinishReadThis;
  1898.     break;
  1899.       case shareware:
  1900.     // Episode 2 and 3 are handled,
  1901.     //  branching to an ad screen.
  1902.       case registered:
  1903.     // We need to remove the fourth episode.
  1904.     EpiDef.numitems--;
  1905.     break;
  1906.       case retail:
  1907.     // We are fine.
  1908.       default:
  1909.     break;
  1910.     }
  1911.     
  1912. }
  1913.  
  1914.